package com.power.sifa.approve.executor.impl;

import com.alibaba.fastjson.JSON;
import com.aventrix.jnanoid.jnanoid.NanoIdUtils;
import com.plf.common.domain.ResponseDTO;
import com.plf.common.domain.YesNo;
import com.plf.common.utils.PdfConvertUtil;
import com.plf.common.utils.WordUtil;
import com.plf.core.base.model.Ha_attachment;
import com.plf.core.base.service.Ha_attachmentService;
import com.power.external.window.api.IWindowFeign;
import com.power.external.window.model.pojo.vo.ApproveVo;
import com.power.external.window.model.pojo.vo.FinishVo;
import com.power.flowable.api.IPersonalFeign;
import com.power.sifa.approve.dao.Aprv_process_materialsDao;
import com.power.sifa.util.executor.AbstractPostExecutor;
import com.power.sifa.approve.model.Apl_admre_audit;
import com.power.sifa.approve.model.Apl_admreview;
import com.power.sifa.approve.model.Apl_main;
import com.power.sifa.approve.model.Aprv_process_materials;
import com.power.sifa.approve.model.enumeration.*;
import com.power.sifa.approve.model.pojo.vo.ProcessVariablesVo;
import com.power.sifa.approve.service.*;
import com.power.sifa.approve.thread.ThreadPoolUtil;
import com.power.sifa.net.service.ApplyService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 生成调解审批表
 */
@Component
@Slf4j
public class AdmreAuditMediate extends AbstractPostExecutor {
    // 用户id
    private String userid;
    // 环节分类标识
    private String category;
    // 用户名
    private String username;
    // 单位id
    private String sectionid;
    // 单位名称
    private String sectionname;
    // 部门id
    private String deptid;
    // 部门名称
    private String deptname;
    // 处理意见
    private String remark;
    // 行政区划
    private String adid;
    // 环节名称
    private String taskname;

    @Resource
    private ApplyService applyService;
    @Resource
    private Apl_mainService apl_mainService;
    @Resource
    private Ha_attachmentService ha_attachmentService;
    @Resource
    private Aprv_process_materialsService aprv_process_materialsService;
    @Resource
    private Apl_admre_auditService apl_admre_auditService;
    @Resource
    private Apl_admreviewService apl_admreviewService;
    @Resource
    private IPersonalFeign iPersonalFeign;
    @Resource
    private Apl_dossierService apl_dossierService;
    @Resource
    private Apl_archiveService apl_archiveService;
    @Resource
    private BusinessApproveService businessApproveService;
    @Resource
    private IWindowFeign iWindowFeign;
    @Resource
    private Aprv_process_materialsDao aprv_process_materialsDao;

    @Override
    public void init(Map<String, Object> initdata) {
        this.userid = (String) initdata.get("userid");
        this.category = (String) initdata.get("category");
        this.username = (String) initdata.get("username");
        this.sectionid = (String) initdata.get("sectionid");
        this.sectionname = (String) initdata.get("sectionname");
        this.deptid = (String) initdata.get("deptid");
        this.deptname = (String) initdata.get("deptname");
        this.remark = (String) initdata.get("remark");
        this.adid = (String) initdata.get("adid");
        this.taskname = (String) initdata.get("taskname");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> execute() throws Exception {
        // 1. 查询子流程的表单数据
        Apl_main mainObj = apl_mainService.getById(super.applyid);
        Map<String, Object> formData = this.applyService.formLoadField(mainObj.getFormid(), super.applyid);
        // 审批表意见和日期字段
        super.ApprovalField(formData);

        // 2. 生成并上传文件
        Ha_attachment attachment;
        byte[] pdfByte;
        WordUtil wordUtil = new WordUtil("AdmreAuditInCharge.docx");
        wordUtil.replaceTable(formData);
        try (OutputStream os = wordUtil.createWord();
             InputStream is = new ByteArrayInputStream(((ByteArrayOutputStream) os).toByteArray())) {
            pdfByte = PdfConvertUtil.word2pdfWithFont(is);
            attachment = ha_attachmentService.upload(new ByteArrayInputStream(pdfByte), "案件调解审批表.pdf");
            log.info("AdmreAuditMediate 案件调解审批表生成并保存成功 -> {}", attachment.getId());
        } catch (Exception e) {
            log.error("AdmreAuditMediate 案件调解审批表生成并保存失败 ->  msg[{}]", e.getMessage());
            throw new RuntimeException("AdmreAuditMediate 案件调解审批表生成并保存失败 -> " + e.getMessage());
        }
        // 3. 保存审批系统文书, 只存父流程
        Apl_admre_audit auditObj = this.apl_admre_auditService.getById(super.applyid);

        Aprv_process_materials docObj = new Aprv_process_materials(Tp_procmaterialEnum.ADMRE_RESULT);
        docObj.setId(auditObj.getApplyid() + NanoIdUtils.randomNanoId());
        // 通知书类型枚举
        docObj.setMattype(Tp_procmaterial.ADMRE_RESULT);
        docObj.setAttachid(attachment.getId());
        docObj.setCreateuserid(this.userid);
        docObj.setCreateuser(this.username);
        docObj.setCreatetime(new Date());
        docObj.setApplyid(auditObj.getApplyid());
        docObj.setType(Tp_proctype.MATER_MEDIATE);
        docObj.setClassify(Tp_classify.DOCUMENT);
        docObj.setSonapplyid(auditObj.getId());
        this.aprv_process_materialsService.saveOrUpdate(docObj);

        Apl_main faMainObj = apl_mainService.getById(auditObj.getApplyid());
        // 3.1  启动一个结果审批流程 (不管要不要市领导审批都需要一个结果审批流程) (调解失败不走结果审批)
        if (YesNo.NO == auditObj.getIssecondout()) {
            // 校验是否上传调解申请书, 决定要不要结果审批流程
            List<Aprv_process_materials> list = this.aprv_process_materialsDao.getByApplyid(faMainObj.getId(), Tp_procmaterial.MATER_MEAPPLY);
            if (!CollectionUtils.isEmpty(list)) {
                Apl_admreview admreObj = this.apl_admreviewService.getById(auditObj.getApplyid());
                Apl_main newMainObj = JSON.parseObject(JSON.toJSONString(mainObj), Apl_main.class);
                Date now = new Date();
                newMainObj.setId(now.getTime() + NanoIdUtils.randomNanoId());
                String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(now);
                newMainObj.setCreatetime(date);
                newMainObj.setCreatetime(date);
                String soninstid = this.businessApproveService.createSonProcess(faMainObj, newMainObj, admreObj, this.userid, "", St_admreview.TOMEDIATE, Tp_proctype.MATER_MEDIATE, auditObj.getIscitymanager(), YesNo.YES);
                // 记录流程变量
                Map<String, Object> variableMap = new HashMap<>(16);
                variableMap.put(ProcessVariablesVo.CITYAPPROVE, auditObj.getIssecondout());
                ResponseDTO res = this.iPersonalFeign.saveVariable(soninstid, variableMap);
                if (0 != res.getCode()) {
                    throw new RuntimeException(res.getMsg());
                }
                // 未配置子流程结束监听器, 手动结束
                this.apl_mainService.updateStatusAndFinishtime(auditObj.getId(), St_apply.FINISH, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                return null;
            }
        }

        // 4. 终止父流程
        ResponseDTO res = this.iPersonalFeign.terminationTask(this.userid, "调解", true, "", faMainObj.getInstid(), this.remark, new ArrayList<>(0));
        if (0 != res.getCode()) {
            log.error("调解终止父流程失败 -> msg[{}]", res.getMsg());
            throw new RuntimeException("调解终止父流程失败" + res.getMsg());
        }

        // 5. 修改业务主表状态为 已调解
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String finishtime = format.format(new Date());
        this.apl_mainService.updateStatusAndFinishtime(auditObj.getApplyid(), St_apply.FINISH, finishtime);
        // 未配置子流程结束监听器, 手动结束
        this.apl_mainService.updateStatusAndFinishtime(auditObj.getId(), St_apply.FINISH, finishtime);
        this.apl_admreviewService.updateStatus(auditObj.getApplyid(), St_admreview.MEDIATE);
        this.apl_admreviewService.updateDecisiondate(auditObj.getApplyid(), finishtime);
        this.apl_admre_auditService.updateStatus(super.applyid, St_admreview.MEDIATE);

        // 6. 初始归档数据
        ThreadPoolUtil.executor.execute(() -> {
            // 6.1 初始化归档首页数据
            this.apl_archiveService.initialArchiveData(faMainObj.getId());
            // 6.2 初始化归档电子卷宗数据
            this.apl_dossierService.buildInitDossier(faMainObj.getId());
        });

        // 刷新文书日期
        this.businessApproveService.processEndedUpdatePreviewDoc(auditObj.getApplyid(), Tp_proctype.MATER_MEDIATE, null);
        // 文书盖章
        this.businessApproveService.templateStamp(auditObj.getApplyid(), Tp_proctype.MATER_MEDIATE);

        // 一窗信息^ 如果是一窗业务, 发送通知
        if (Tp_applysource.WINDOW == faMainObj.getSource()) {
            ThreadPoolUtil.executor.execute(() -> {
                // 不予受理结果通知
                ApproveVo appVo = new ApproveVo();
                appVo.setOpinion("不予受理");
                appVo.setResult("0"); // 1 受理 0 不予受理
                appVo.setUserid(userid);
                appVo.setUsername(username);
                appVo.setTime(finishtime);
                ResponseDTO conRef = this.iWindowFeign.confirmAccept(auditObj.getApplyid(), appVo);
                if (0 != conRef.getCode()) {
                    log.error("向一窗推送不予受理结果失败 applyid -> {}", faMainObj.getId());
                }
                // 办结结果通知
                FinishVo finVo = new FinishVo();
                finVo.setOpinion("不予许可");
                finVo.setResult("0"); // 0 不予许可, 1 许可通过, 109 审批出件, 96 退件办结
                finVo.setUserid(userid);
                finVo.setUsername(username);
                finVo.setTime(format.format(new Date()));
                finVo.setLicenceName("不予受理行政复议申请决定书");
                finVo.setLicenceCode(mainObj.getAcceptcode());
                ResponseDTO subRes = this.iWindowFeign.submitResult(auditObj.getApplyid(), finVo);
                if (0 != subRes.getCode()) {
                    log.error("向一窗推送业务办理结果失败 applyid -> {}", faMainObj.getId());
                }
            });
        }
        return null;
    }
}

